#include <iostream>
#include <memory>
#include <vector>
#include <functional>
#include <unordered_map>
#include <unistd.h>

using Task_Func = std::function<void()>;
using Release_Func = std::function<void()>;

class TimerTask
{
private:
    uint64_t _id;             // 任务的id
    uint32_t _timeout;        // 任务的延时时间
    bool _cancel;             // 表示当前任务是否被取消
    Task_Func _task_cb;       // 执行任务的回调函数
    Release_Func _release_cb; // 释放当前任务在时间轮中的映射
public:
    TimerTask(uint64_t id, uint32_t delay, const Task_Func &tcb)
        : _id(id), _timeout(delay), _task_cb(tcb), _cancel(false)
    {
    }
    ~TimerTask()
    {
        if (!_cancel)
            _task_cb();
        _release_cb();
    }

public:
    void SetRelease(const Release_Func &rcb)
    {
        _release_cb = rcb;
    }

    void SetCancel()
    {
        _cancel = true;
    }

    uint32_t Timeout()
    {
        return _timeout;
    }
};

class TimerWheel
{
private:
    using WeakTask = std::weak_ptr<TimerTask>;
    using TaskPtr = std::shared_ptr<TimerTask>;
    const static int defaultsize = 60;

private:
    int _tick;                                      // 当前的时间指针，走到哪里就释放哪里的所有延时任务节点
    std::vector<std::vector<TaskPtr>> _wheel;       // 存放延时任务定时器的时间轮数组
    std::unordered_map<uint64_t, WeakTask> _timers; // id和对应任务weak_ptr的映射关系
private:
    void RemoveTimer(uint64_t id)
    {
        auto it = _timers.find(id);
        if (it == _timers.end())
            return;
        _timers.erase(it);
    }

public:
    TimerWheel() : _tick(0), _wheel(defaultsize)
    {
    }
    void AddTimer(uint64_t id, uint32_t delay, const Task_Func &tcb)
    {
        TaskPtr tp(new TimerTask(id, delay, tcb));
        tp->SetRelease(std::bind(&TimerWheel::RemoveTimer, this, id));
        _wheel[delay].push_back(tp);
        _timers[id] = WeakTask(tp);
    }

    void RefreshTimer(uint64_t id)
    {
        auto it = _timers.find(id);
        // 找不到当前任务的id
        if (it == _timers.end())
            return;
        TaskPtr tp = it->second.lock();
        uint32_t timeout = tp->Timeout();
        // 注意：时间指针是循环增加的
        int pos = (_tick + timeout) % _wheel.size();
        _wheel[pos].push_back(tp);
        std::cout << "pos:" << pos <<std::endl;
    }

    void RunTimerTask()
    {
        _tick = (_tick + 1) % _wheel.size();
        std::cout << "tick:" << _tick <<std::endl;
        _wheel[_tick].clear();
    }
};

class Test
{
public:
    Test() {std::cout << "构造函数" << std::endl;}
    ~Test() {std::cout << "析构函数" << std::endl;}
};

void Testfunc()
{
    Test t;
}

int main()
{
    TimerWheel tw;

    tw.AddTimer(1,5,std::bind(Testfunc));

    for(int i = 0; i < 5; ++i)
    {
        sleep(1);
        tw.RefreshTimer(1);
        tw.RunTimerTask();
        std::cout << "刷新定时任务, 5s后执行任务..." << std::endl;
    }

    while(1)
    {
        sleep(1);
        tw.RunTimerTask();
        std::cout << "----------------" << std::endl;
    }

    return 0;
}
